#include <bits/stdc++.h>
#include <stdbool.h>
using namespace std;

const int maxn = 300;

// 并查集类
// 将并查集的数据 int fa[100];
// 以及并查集的操作 int root(int x) / void merge(int x, int y)
// 放在一起，形成一个独立的类
class DisjointSet
{
// 并查集数据
    int n;
    int fa[305];

// 并查集操作
public:
    DisjointSet(const int &k):n(k)
    {
        for(int i=1; i<=k; i++)
            fa[i] = i;
    }

    int root(int i)
    {
        if(fa[i] == i)
            return i;
        
        return fa[i] = root(fa[i]);
    }

    bool merge(int x, int y)
    {
        int rx = root(x);
        int ry = root(y);

        if(rx == ry)
            return false;
        
        fa[rx] = ry;
        return true;
    }
};

// 边 (u, v, w)
struct Edge
{
    int u;
    int v;
    int w;
};

// 针对边权值的比较器
bool cmp(struct Edge e1, struct Edge e2)
{
    return e1.w < e2.w;
}

struct Edge E[maxn*maxn/2]; // 边表
struct Edge *p = E;

int price[maxn];
int ans; // 最小生成树的最终权值总和

void addEdge(int u, int v, int w)
{
    p->u = u;
    p->v = v;
    p->w = w;
    p++;
}

// 使用加边法最小生成树
void Kruskal(DisjointSet miner)
{
    // 对每条边的权值进行排序
    sort(E, p, cmp);

    // 按权值从小到大遍历各条边
    // 将符合条件的边加入MST
    for(Edge *i=E; i<p; i++)
    {
        // 如果该边未加入MST，那么将其加入
        if(miner.merge(i->u, i->v))
        {
            ans += i->w;
        }
    }
}

int main(int argc, char const *argv[])
{
    // 生成一个有k个矿井的并查集
    int k;
    cin >> k;
    DisjointSet miner(k);

    // 读取k个矿井电站的费用
    for(int i=1; i<=k; i++)
        cin >> price[i];

    // 读取(k*k)/2个边权值
    int tmp;
    for(int i=1; i<=k; i++)
    {
        for(int j=1; j<=k; j++)
        {
            cin >> tmp;
            if(j>i)
                // 不断填充边表
                addEdge(i, j, tmp); // 无向边
        }
    }

    // 虚拟矿井为k+1，与原图各点链表
    // 将原先k个矿井电站的费用视为虚拟矿井拉电线的费用
    for(int i=1; i<=k; i++)
        addEdge(i, k+1, price[i]);

    // 克鲁斯卡尔（加边法）构造最小生成树（MST）的流程
    Kruskal(miner);
    cout << ans << endl;

    return 0;
}